package com.fengwk.support.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import com.fengwk.support.exception.BaseException;
import com.fengwk.support.util.LoggerUtils.Logger;

/**
 * 工具类:操作时间日期
 */
public final class DateUtils {
	
	private static final Logger LOG = LoggerUtils.getLogger(DateUtils.class);
	
	/**
	 * yyyy-MM-dd hh:mm:ss
	 */
	public final static String DEFAULT = "yyyy-MM-dd HH:mm:ss";
	
	/**
	 * yyyy-MM-dd
	 */
	public final static String YYYYMMDD = "yyyy-MM-dd";
	
	/**
	 * yyyy/MM/dd
	 */
	public final static String WORDDATE = "yyyy/MM/dd";
	
	/**
	 * 默认本机TIME_ZONE_ID
	 */
	public final static String DEFAULT_TIME_ZONE_ID = TimeZone.getDefault().getID();
	
	private DateUtils() {
		throw new BaseException("can not instance " + getClass());
	}
	
	/**
	 * 获取当前Date
	 * 
	 * @return
	 */
	public static Date current() {
		return new Date();
	}
	
	/**
	 * 获取当前时间的格式化字符串
	 * 
	 * @param format
	 * @return
	 */
	public static String current(String format) {
		return format(current(), format);
	}
	
	/**
	 * 获取当前时间Calendar
	 * 
	 * @return
	 */
	public static Calendar currentCalendar() {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(current());
		return calendar;
	}
	
	/**
	 * 获取当前时间戳
	 * 
	 * @return
	 */
	public static long getTime() {
		return System.currentTimeMillis();
	}
	
	/**
	 * 格式化日期为 yyyy-MM-dd HH:mm:ss
	 * 
	 * @param date
	 * @return
	 */
	public static String format(Date date) {
		return format(date, DEFAULT);
	}
	
	/**
	 * 格式化日期
	 * 
	 * @param date
	 * @param format 格式
	 * @return
	 */
	public static String format(Date date, String format) {
		return (date == null) ? "" : new SimpleDateFormat(format).format(date);
	}
	
	/**
	 * 字串依照yyyy-MM-dd格式转为日期
	 * 
	 * @param dateStr
	 * @return
	 */
	public static Date toDate(String dateStr) {
		return toDate(dateStr, DEFAULT);
	}
	
	/**
	 * 字串依照format格式转为日期
	 * 
	 * @param dateStr
	 * @param format 格式
	 * @return
	 */
	public static Date toDate(String dateStr, String format) {
		Date date = null;
		if (dateStr != null && !dateStr.equals("")) {
			DateFormat df = new SimpleDateFormat(format);
			try {
				date = df.parse(dateStr);
			} catch (ParseException e) {
			    LOG.error(e);
			}
		}
		return date;
	}
	
	/**
	 * 间隔分钟
	 * 
	 * @param begin
	 * @param end
	 * @return
	 */
	public static long minuteInterval(Date begin, Date end) {
		return (end.getTime() - begin.getTime()) / (60 * 1000);
	}
	
	/**
	 * 流逝分钟
	 * 
	 * @param beginDate 开始时间
	 * @return
	 */
	public static long passMinute(Date beginDate) {
		return minuteInterval(beginDate, current());
	}
	
	/**
	 * 流逝时间
	 * 
	 * @param beginTime 开始时间
	 * @return 返回至现在流逝的时间(单位毫秒)
	 */
	public static long passTime(Long beginTime) {
		return System.currentTimeMillis() - beginTime;
	}
	
	/**
	 * 流逝时间
	 * 
	 * @param startDate 开始时间
	 * @return 返回至现在流逝的时间(单位毫秒)
	 */
	public static long passTime(Date startDate) {
		return passTime(startDate.getTime());
	}

	/**
	 * 获取星期
	 * 
	 * @param date
	 * @return
	 */
	public static String getWeekOfDate(Date date) {
		String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);

		int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (w < 0) {
			w = 0;
		}
		return weekDays[w];
	}
	
	/**
	 * 获取当前年份
	 * 
	 * @param timeZone
	 * @return
	 */
	public static int getCurrentYear(String timeZoneId) {
		if (StringUtils.isEmpty(timeZoneId)) {
			return Calendar.getInstance().get(Calendar.YEAR);
		}
		return Calendar.getInstance(TimeZone.getTimeZone(timeZoneId)).get(Calendar.YEAR);
	}

	/**
	 * 获指定日期的Calendar
	 * 
	 * @param date
	 * @param timeZone
	 * @return
	 */
	public static Calendar getCalendar(Date date, String timeZoneId) {
		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(timeZoneId));
		calendar.setTime(date);
		return calendar;
	}

	/**
	 * 一天开始时间
	 * 
	 * @param date
	 * @return
	 */
	public static Date getStartOfDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		Date start = calendar.getTime();
		return start;
	}

	/**
	 * 一天结束时间
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndOfDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		Date end = calendar.getTime();
		return end;
	}
	
	/**
	 * 相同日期比对
	 * 
	 * @param first
	 * @param second
	 * @return 同一天返回true
	 */
	public static boolean isSameDay(Date first, Date second){
		Calendar fc = Calendar.getInstance();
		fc.setTime(first);
		Calendar sc = Calendar.getInstance();
		sc.setTime(second);
		boolean result = (fc.get(Calendar.YEAR) == sc.get(Calendar.YEAR))&&
				(fc.get(Calendar.MONTH) == sc.get(Calendar.MONTH))&&
				(fc.get(Calendar.DAY_OF_MONTH) == sc.get(Calendar.DAY_OF_MONTH));
		return result;
	}
	
	/**
	 * 比对日期是否为今天
	 * 
	 * @param date 比对日期
	 * @return
	 */
	public static boolean isNowDay(Date date) {
		return isSameDay(date, current());
	}
	
	/**
	 * 传入指定格式format,返回传入日期是否为今天
	 * 
	 * @param dateStr
	 * @param format
	 * @return
	 */
	public static boolean isNowDay(String dateStr, String format) {
		return isNowDay(toDate(dateStr, format));
	}
	
	/**
	 * 传入指定格式 yyyy-MM-dd,返回传入日期是否为今天
	 * 
	 * @param dateStr
	 * @return
	 */
	public static boolean isNowDay(String dateStr) {
		return isNowDay(dateStr, YYYYMMDD);
	}
	
	/**
	 * 日期加法,单位日
	 * 
	 * @param date
	 * @param days
	 * @return
	 */
	public static Date addDays(Date date, int days) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DAY_OF_YEAR, days);
		Date now = calendar.getTime();
		return now;
	}
	
	/**
	 * 日期加法,单位月
	 * 
	 * @param date
	 * @param amount
	 * @return
	 */
	public static Date addMonths(final Date date, final int amount) {
        return add(date, Calendar.MONTH, amount);
    }
	
	// 日期加法
	private static Date add(final Date date, final int calendarField, final int amount) {
        if (date == null) {
            throw new IllegalArgumentException("The date must not be null");
        }
        final Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }
	
	public static List<String> listDateBetweenWithStr(String beginDateStr, String endDateStr) {
		return listDateBetweenWithStr(beginDateStr, endDateStr, YYYYMMDD);
	}
	
	public static List<String> listDateBetweenWithStr(Date beginDate, Date endDate) {
		return listDateBetweenWithStr(beginDate, endDate, YYYYMMDD);
	}
	
	public static List<String> listDateBetweenWithStr(String beginDateStr, String endDateStr, String format) {
		return listDateBetweenWithStr(toDate(beginDateStr, format), toDate(endDateStr, format), format);
	}
	
	public static List<String> listDateBetweenWithStr(Date beginDate, Date endDate, String format) {
		long beginTime = beginDate.getTime();
		long endTime = endDate.getTime();
		if(endTime < beginTime) {
			throw new BaseException("endDate less than beginDate");
		}
		List<String> list = new ArrayList<String>();
		Calendar c = Calendar.getInstance();
		c.setTime(beginDate);
		while(true) {
			Date currentDate = c.getTime();
			list.add(format(currentDate, format));
			if(currentDate.getTime() >= endTime) {
				break;
			}
			c.add(Calendar.DATE, 1);
		}
		return list;
	}
	
	public static Map<Integer, List<String>> getWeekDateBetweenOrderMapWithWeek(String beginDateStr, String endDateStr) {
		return getWeekDateBetweenOrderMapWithWeek(listDateBetweenWithStr(beginDateStr, endDateStr));
	}
	
	public static Map<Integer, List<String>> getWeekDateBetweenOrderMapWithWeek(Date beginDate, Date endDate) {
		return getWeekDateBetweenOrderMapWithWeek(listDateBetweenWithStr(beginDate, endDate));
	}
	
	public static Map<Integer, List<String>> getWeekDateBetweenOrderMapWithWeek(String beginDateStr, String endDateStr, String format) {
		return getWeekDateBetweenOrderMapWithWeek(listDateBetweenWithStr(beginDateStr, endDateStr, format));
	}
	
	public static Map<Integer, List<String>> getWeekDateBetweenOrderMapWithWeek(Date beginDate, Date endDate, String format) {
		return getWeekDateBetweenOrderMapWithWeek(listDateBetweenWithStr(beginDate, endDate, format));
	}
	
	public static Map<Integer, List<String>> getWeekDateBetweenOrderMapWithWeek(List<String> dayStrList) {
		Map<Integer, List<String>> resMap = new LinkedHashMap<Integer, List<String>>();
		Calendar cBegin = Calendar.getInstance();
		Calendar cEnd = Calendar.getInstance();
		cBegin.setTime(toDate(dayStrList.get(0), YYYYMMDD));
		cEnd.setTime(toDate(dayStrList.get(dayStrList.size() - 1), YYYYMMDD));
		cEnd.add(Calendar.DATE, 1);
	    int count = 1;
	    int i = 0;
	    while(cBegin.before(cEnd)) {
	    	List<String> weekDayList = resMap.get(count);
	    	if(weekDayList == null) {
	    		weekDayList = new ArrayList<String>();
	    		resMap.put(count, weekDayList);
	    	}
	    	weekDayList.add(dayStrList.get(i ++));
	    	if(cBegin.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY){
	    		count++;
	    	}
	    	cBegin.add(Calendar.DAY_OF_YEAR, 1);
	    }
	    return resMap;
	}
	
	public static Map<String, Integer> getDateBetweenOrderWeekMapWithWeek(String beginDateStr, String endDateStr) {
		return getDateBetweenOrderWeekMapWithWeek(listDateBetweenWithStr(beginDateStr, endDateStr));
	}
	
	public static Map<String, Integer> getDateBetweenOrderWeekMapWithWeek(Date beginDate, Date endDate) {
		return getDateBetweenOrderWeekMapWithWeek(listDateBetweenWithStr(beginDate, endDate));
	}
	
	public static Map<String, Integer> getDateBetweenOrderWeekMapWithWeek(String beginDateStr, String endDateStr, String format) {
		return getDateBetweenOrderWeekMapWithWeek(listDateBetweenWithStr(beginDateStr, endDateStr, format));
	}
	
	public static Map<String, Integer> getDateBetweenOrderWeekMapWithWeek(Date beginDate, Date endDate, String format) {
		return getDateBetweenOrderWeekMapWithWeek(listDateBetweenWithStr(beginDate, endDate, format));
	}
	
	public static Map<String, Integer> getDateBetweenOrderWeekMapWithWeek(List<String> dayStrList) {
		Map<String, Integer> resMap = new LinkedHashMap<String, Integer>();
		Calendar cBegin = Calendar.getInstance();
		Calendar cEnd = Calendar.getInstance();
		cBegin.setTime(toDate(dayStrList.get(0)));
		cEnd.setTime(toDate(dayStrList.get(dayStrList.size() - 1)));
		cEnd.add(Calendar.DATE, 1);
	    int count = 1;
	    int i = 0;
	    while(cBegin.before(cEnd)) {
	    	resMap.put(dayStrList.get(i ++), count);
	    	if(cBegin.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY){
	    		count++;
	    	}
	    	cBegin.add(Calendar.DAY_OF_YEAR, 1);
	    }
	    return resMap;
	}
	
	public static Date beforeDay(Date date, int day) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - day);
		return calendar.getTime();
	}
	
	public static Date beforeWeek(Date date, int week) {
		return beforeDay(date, 7 * week);
	}
	
	public static Date beforeYear(Date date, int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - year);
		return calendar.getTime();
	}
	
	public static Date afterDay(Date date, int day) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + day);
		return calendar.getTime();
	}
	
	public static Date afterWeek(Date date, int week) {
		return afterDay(date, 7 * week);
	}
	
	public static Date afterYear(Date date, int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + year);
		return calendar.getTime();
	}
	
}
